Working on projects in R is typically an iterative experience. You write a function, record the results, explore the results with plots, improve your functions, rinse and repeat. Repeat for just a little while and you end up with an environment filled with forgotten names and a script half a mile long (speaking from personal experience).

This iterative process is especially true for QTL mapping experiments in R. Even with high-quality data in hand, it may not be obvious what the proper mapping technique you should use, or what parameters should be used for a given technique. The process of choosing the appropriate model and model parameters has to instead be tailored to the organism, trait, and structure of the data for each experiment on a case-by-case basis.

In practice, this involves fitting many models, and inspecting the results of each model and how they compare to one another. Keeping track of the models alone can quickly become difficult, let alone how they compare with one another.

One option to alleviate some of these challenges is to use workflow management software which provide an organizational framework for projects in R (and other languages). One such package in R is targets. In the authors words:

The targets package is a Make-like pipeline toolkit for Statistics and data science in R. With targets, you can maintain a reproducible workflow without repeating yourself. targets skips costly runtime for tasks that are already up to date, runs the necessary computation with implicit parallel computing, and abstracts files as R objects. A fully up-to-date targets pipeline is tangible evidence that the output aligns with the code and data, which substantiates trust in the results.

In general, using these management tools allow researchers to efficiently manage, understand, and communicate the results of projects that would be frustrating for the programmer to keep track of, and difficult for someone new to the code to understand. Furthermore, these packages are designed to ensure that the results obtained are reproducible so that both you and anyone you share the code with can have confidence in the consistency of the results you obtain.

The targets package also has an ecosystem of side “helper” packages that augment its base capabilities. These include tflow to easily set up projects that use targets, fnmate to define functions in targets projects with simple shortcuts, and the targetopia collection of target-adjacent packages for more specialized applications.

Beyond providing an organizational framework, targets steers users towards a workflow which makes heavy use of functional programming. This allows users to create analysis plans that are both compact and very flexible.

I’ve become very fond these packages, and end up using them in just about every project I do beyond the most trivial of jobs. The goal of this document is to both show how to use the targets package to implement a QTL mapping pipeline, and demonstrate why I like using it and its related packages so much.

This blog post by the author of the tflow and fnmate packages is an especially good (and accessible) overview of the benefits of using these workflows, and how to implement them. It almost single-handedly convinced me to start using these packages. The drake package mentioned in the post is however the predecessor of the targets package. The syntax has changed a bit between the two packages, but the overall goals and design has remained largely the same. Theres even a chapter in the targets manual dedicated to explaining the differences between the two.

Some other potentially helpful links are this general overview

QTL Mapping

Before I go into the actual implementation, I’ll (briefly) go over a very general QTL mapping workflow.

Techniques

r/qtl provides several techniques for performing QTL mapping. Broadly, these may be broken down in terms of those designed to estimate the effects of single QTL, and those designed to estimate the effects of multiple QTL which act simultaneously to influence some trait. In r/qtl the single QTL methods are implemented with the scanone function, and the multi-QTL methods are implemented with the cim, stepwiseqtl , and mqmscan functions for composite interval mapping , multiple interval mapping through forward/backward search, and multiple QTL mapping (MQM) respectively.

A layer of difficulty is added by the multi-QTL models as each has a number of parameters which must be supplied by a user and it is not always obvious what the best choice should be. As an example, in composite interval mapping, a user must supply the number of marker cofactors to use in the analysis, and a window size (in cM). Appropriate values to choose for these parameters is not always clear, and it is typically best to try different combinations, and compare the results you get.

Significance Thresholds

Once a scan is performed with some technique, a user then has to decide what qualifies as a significant QTL. Evidence for a QTL is typically given as a logarithm of odds (LOD) score where higher values indicate more evidence in favor of the presence of a QTL at some location. To determine an appropriate threshold for declaring significance, a permutation test is typically performed. This involves randomizing the phenotype data against the genotype data, performing a scan for QTL, and recording the highest LOD score obtained. By repeating this procedure many times, a user can generate a distribution of LOD scores that you would expect to see if there was no association between the phenotypes and genotypes for your specific data set. A user can the select a percentile of this distribution and declare any QTL with a LOD score above that threshold to be significant.

Estimating effects

Once a set of significant QTL has been found, the next step is to obtain information about the QTL themselves. This often includes statistics like how much of the phenotypic variation can be explained by the QTL, its additive effect, a LOD score, and others. In r/qtl this information is obtained with the fitqtl function.

General workflow

Below I made a simple flowchart to show the general steps for the QTL mapping analysis. These are the general steps that I will incorporate into the workflow I implement with targets. In practice, the analysis flow chart itself will be more complicated, but I’ll get to that in a bit.

You can see that the main differences between the single and multi-QTL mapping paths stem from the fact that you have to evaluate the effect of the different parameters supplied to the model. This isn’t to say that using the single-QTL mapping techniques don’t involve specifying important model parameters, but in most cases, a researcher will have a good idea what an appropriate choice would be from the onset of the experiment in contrast to the parameters for the multi-QTL techniques that are more subjective.

QTL mapping with targets

In this section, I’m going to talk about some functionality of targets that have been really useful for running QTL analyses. While I’ll try to go into detail on some of the most important functions for this, I wont be able to cover all the inns and outs of targets, and running a targets project. That being said, the package authors have written a very good user manual to go over all the fine details of using the package. In case you haven’t read this blog post yet, do it. It was really helpful for getting me up and running with drake, and the concepts carry over almost seamlessly to targets. I’d suggest that if you haven’t used the package yet, start with the blog post and then check out the manual.

With the general QTL mapping flowchart above, the next part is how to actually go about implementing it in code. Translating a conceptual flowchart like the one above to code in targets is actually (relatively) straightforward. Briefly, targets requires you to have a specially formatted “master” script file that tells R what tasks you want to perform, and how you will perform them. The “what” part is just a name, and the “how” part given through function calls. A target is essentially just a name a function, and a workflow is a series of these targets that you tie together by using the output of one target as the input to another. In terms of the flowchart above, the “what” is the name of the shapes, and the “how” is what you do to move from one shape to the next. targets then works by analyzing the code in your master script to build a directed graph of analysis tasks. When you run a workflow, this graph is then used to calculate tasks in the order in which they show up. This graph structure is also what targets uses to keep an analysis up to date. If you change a function that is used in an early target, you can see what output is affected by seeing what downstream targets are connected to the target that uses the changed function as a command.

There’s a few ways to go about implementing a workflow in targets, but I like using the tar_plan function which comes from the tarchetypes package. Briefly, this function wraps a series of target definitions using a special format. To give an example, here’s what the QTL mapping plan looks like with just the first four targets. tar_target is the function you use to define a target. The first argument to the function is the name of the target, the second is the “command”, what the target needs to do. There’s many other available arguments, but you can do a whole lot with just these two.

For now, ignore all the text in the script before the tar_plan call. In the plan below, the first target is named InputFile. It just defines where I have the .csv cross stored on my computer. The following targets read in the cross, perform QTL mapping with single marker regression and perform permutations with single marker regression. There’s a couple things to note here. First, you can see the special format argument in the first target. This lets the workflow know that this target is an external file. In the second target, I used a different way to name the target. This is the naming scheme from drake where you assign the output of the target command to the target name. In practice, this is equivalent too the following two target definitions which have the name in the first argument position of the function, and the command given by the custom function call in the second position.


A simple plan (click the triangle to show/hide)
## Load your packages, e.g. library(targets).
source("./packages.R")

## Load your R files
lapply(list.files("./R", full.names = TRUE), source)

## tar_plan supports drake-style targets and also tar_target()
tar_plan(
  
  # The input cross data, already in the r/qtl "csv" format
  tar_target(InputFile, 
             "Data/ExampleCross.csv",
             format = "file"),
  
  # Read the QTL file in with r/qtls "read.cross" function. Also apply
  # a few basic operations to clean the initial cross
  QTLData = read_cross(QTL_File = InputFile),
  
  # Marker regression mapping
  tar_target(RegressionResults,
             Map_Regression(CrossData = QTLData,
                                Pheno = phenames(QTLData))),
  
  # Permutations for the marker regression
  tar_target(RegressionPerms,
             Map_Regression_Perms(CrossData = QTLData,
                                  Pheno     = phenames(QTLData),
                                  nPerm     = 100))
  
)


To give more detail, look at what the (barely) custom Map_Regression function from the third target (RegressionResults) looks like.


marker regression function
Map_Regression <- function(CrossData = QTLData, Pheno = phenames(QTLData)) {

  # Just a wrapper for scanone with the method set, and arguments 
  # supplied in names defined in the workflow
  scanone(cross     = CrossData, 
          pheno.col = Pheno,
          method    = "mr")

}


You can see why I say “barely”. This function is just a wrapper for the scanone function from r/qtl with the method set to marker regression, and slightly different argument names. You could just as easily use the scanone function alone, I only wrapped the function so that it would be more obvious what I was doing when I read through my plan.

Now would be a good time to introduce another helpful function. At any point, you can see the underlying graph that drives the workflow with the tar_visnetwork function. Here is what this network looks like right now with just these four targets.

<!DOCTYPE html> visNetwork

This is a pretty straightforward workflow, and it’s not very different than what you would get by writing a standard R script. Things get more interesting when we start to fit many models, and compare their results.

The cim function from r/qtl is used to perform composite interval mapping. This function has two main parameters: the number of marker cofactors, and the window size. When performing a qtl mapping experiment, you might want to try different combinations of these parameters and inspect the results of each combination. This is where targets really starts to shine.

Here’s what the plan looks like after I added some functions to perform composite interval mapping with many different parameter combinations.


The plan with composite interval mapping added
## Load your packages, e.g. library(targets).
source("./packages.R")

## Load your R files
lapply(list.files("./R", full.names = TRUE), source)

AllPhenos <- c("EarHeight",
               "LeafLength",
               "LeafWidth",
               "CobWeight",
               "TotalKernelVolume")

# Combinations of parameters for composite interval mapping.
# Useful early on for checking the effects of different model parameters on the output
CIM_ModelParams <- expand_grid(
  CIM_n.marcovar = c(5, 7, 10),
  CIM_Window     = c(10, 15, 20),
  PhenoNames     = AllPhenos
)

## tar_plan supports drake-style targets and also tar_target()
tar_plan(
  
  # The input cross data, already in the r/qtl "csv" format
  tar_target(InputFile, 
             "Data/ExampleCross.csv",
             format = "file"),
  
  # Read the QTL file in with r/qtls "read.cross" function. Also apply
  # a few basic operations to clean the initial cross
  QTLData = read_cross(QTL_File = InputFile),
  
  # Marker regression mapping and permutations
  tar_target(RegressionResults,
             Map_Regression(CrossData = QTLData,
                                Pheno = phenames(QTLData))),
  
  tar_target(RegressionPerms,
             Map_Regression_Perms(CrossData = QTLData,
                                  Pheno     = phenames(QTLData),
                                  nPerm     = 100)),
  

  # Simple interval mapping and permutations
  tar_target(SimpleIntervalResults,
             Map_SimpleInterval(CrossData   = QTLData,
                                      Pheno = phenames(QTLData))),
  
  tar_target(SimpleIntervalPerms,
             Map_SimpleInterval_Perms(CrossData = QTLData,
                                      Pheno     = phenames(QTLData),
                                      nPerm     = 100)),
  
  # Composite interval mapping
  # Perform composite interval mapping with each combination of phenotype,
  # number of marker covariates, and window size as specified above
  CIM_Mapped <- tar_map(
    
    values = CIM_ModelParams,
    
    tar_target(CompositeIntervalResults,
               Map_Composite(CrossData  = QTLData,
                             Pheno      = PhenoNames,
                             nCovar     = CIM_n.marcovar,
                             WindowSize = CIM_Window,
                             perm       = F))
    
  )
)


A first thing to notice are the AllPhenos vector and the CIM_ModelParams tibble before the call to tar_plan. AllPhenos is a vector which says what phenotypes I want to perfrom QTL mapping on, and the CIM_ModelParams is a table that holds every combination of model parameters (number of marker cofactors, window size, and phenotype) that I want to try in composite interval mapping. In this case, I used the expand_grid function to return a tibble with a row for every combination of the three paramater vectors. I supplied three numbers of marker cofactors, three window sizes, and 5 phenotypes, so this table has a total of 45 (3 x 3 x 5) rows; one for each unique parameter combination.

Normally, fitting a model for each of these combinations would be relatively cumbersome to implement in base R, and even harder to keep the results organized. In targets, a solution to this repetition of the same analysis task with different parameter combinations is already provided through branching. In short, this allows you to supply a target with a data structure that holds named parameter values which can then be accessed by a function in a target that has arguments which refer to each parameter value by its name in the data structure.

A user can then define a pattern when using dynamic branching, or use helper functions from tarchetypes when using static branching to describe how the values in this data structure should be used to create a whole set of targets.

In that plan above, I give the parameter combinations in the CIM_ModelParams tibble up front, and actually define the new targets in the CIM_Mapped step. The tar_map function I use there is a special helper function from tarchetypes. This uses similar logic to the map function from purrr where the function you give in the target definition(s) is applied to each parameter(s) you provide with the value argument. In the example above, you can see that the CompositeIntervalResults target calls the Map_Composite function which takes as arguments a cross object, a number of marker cofactors, a window size, and a phenotype. The values given for these arguments match the names of the paramaters given in the CIM_ModelParams tibble, with the exception of the cross object which is provided through the name of the upstream target that holds the cross. This is how targets figures out which targets need to be created, and what commands (function calls) need to be performed for each.

At this point, it may be helpful to check up on what the graph looks like now.
<!DOCTYPE html> visNetwork


With just a few lines, you can create a huge number of new analyses. By scrolling in on that graph, you can also see that targets has named each target according to the parameter values that were mapped to each function call. As an example, the target names CompositeIntervalResults_5_15_LeafLength gets its name from **TargetName_“CIM_n.marcovar”_“CIM_Window”_PhenoNames** the order of the paramaters min the target name matches the order of the names in the value object, in this case the CIM_ModelParams tibble.

At this point, the value of any one target can be read by calling tar_read(“Target name”). This is helpful for checking that you are getting the output you’d expect, but again gets very cumbersome when you are woring with a large number of targets. A straightforward solution to this is to use another helper function, tar_combine. As the name suggests, this function takes several upstream targets, and combines them into a single new target. This function just requires a name, what targets you want to combine, and how you want the results of targets to be combined.

Here’s what the plan and it’s graph look like after tar_combine is added to the plan.


Combining the results
## Load your packages, e.g. library(targets).
source("./packages.R")

## Load your R files
lapply(list.files("./R", full.names = TRUE), source)

AllPhenos <- c("EarHeight",
               "LeafLength",
               "LeafWidth",
               "CobWeight",
               "TotalKernelVolume")

# Combinations of parameters for composite interval mapping.
# Useful early on for checking the effects of different model parameters on the output
CIM_ModelParams <- expand_grid(
  CIM_n.marcovar = c(5, 7, 10),
  CIM_Window     = c(10, 15, 20),
  PhenoNames     = AllPhenos
)

## tar_plan supports drake-style targets and also tar_target()
tar_plan(
  
  # The input cross data, already in the r/qtl "csv" format
  tar_target(InputFile, 
             "Data/ExampleCross.csv",
             format = "file"),
  
  # Read the QTL file in with r/qtls "read.cross" function. Also apply
  # a few basic operations to clean the initial cross
  QTLData = read_cross(QTL_File = InputFile),
  
  # Marker regression mapping and permutations
  tar_target(RegressionResults,
             Map_Regression(CrossData = QTLData,
                                Pheno = phenames(QTLData))),
  
  tar_target(RegressionPerms,
             Map_Regression_Perms(CrossData = QTLData,
                                  Pheno     = phenames(QTLData),
                                  nPerm     = 100)),
  

  # Simple interval mapping and permutations
  tar_target(SimpleIntervalResults,
             Map_SimpleInterval(CrossData   = QTLData,
                                      Pheno = phenames(QTLData))),
  
  tar_target(SimpleIntervalPerms,
             Map_SimpleInterval_Perms(CrossData = QTLData,
                                      Pheno     = phenames(QTLData),
                                      nPerm     = 100)),
  
  # Composite interval mapping
  # Perform composite interval mapping with each combination of phenotype,
  # number of marker covariates, and window size as specified above
  CIM_Mapped <- tar_map(
    
    values = CIM_ModelParams,
    
    tar_target(CompositeIntervalResults,
               Map_Composite(CrossData  = QTLData,
                             Pheno      = PhenoNames,
                             nCovar     = CIM_n.marcovar,
                             WindowSize = CIM_Window,
                             perm       = F))
    
  ),
  
  # Combine the results to a single list
   tar_combine(CompositeIntervalResults_Combined,
               CIM_Mapped[[1]],
               command = list(!!!.x)),
  
  # A simple flowchart for the general QTL mapping process (used in the writeup)
   tar_target(QTL_Flowchart, 
           make_flowchart()),
  
  # Render the analysis writeup
   tar_render(AnalysisWriteup, "docs/AnalysisWriteup.Rmd")
)



<!DOCTYPE html> visNetwork


There’s three arguments in the tar_combine function in that plan, the first is just the target name, the second says what targets you want to combine, and the third (the command) says how you want to combine the targets. In my example, I named the new target CompositeIntervalResults_Combined, in the second argument, I specify the targets I want to combine by pulling them from the CIM_Mapped target. I do this by using list indexing, and selecting the first list element. Looking at the structure of the CIM_Mapped target might help to clarify this.

all_of(CIM_Mapped) %>% typeof()
## [1] "list"
all_of(CIM_Mapped) %>% str()
## List of 1
##  $ CompositeIntervalResults:List of 45
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x0000000019e7dba8> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x0000000019de6d98> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x00000000199b90b8> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x0000000019808fb0> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x000000001872b9a0> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x000000001860f530> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x0000000017dbdf10> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x0000000017bd62b8> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x00000000179860f0> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x00000000157fb4a0> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x00000000164d0790> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x0000000015753c30> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x000000001ffa4448> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x000000001e2d3190> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x000000001fdbd4f0> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x00000000201004b0> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x000000002018a0e0> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x000000002020a7c8> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x00000000202b49c0> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x0000000020329e00> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x000000002038f390> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x00000000204547f0> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x00000000204f9dc8> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x000000002057a4e8> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x00000000205dfea0> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x0000000020645890> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x00000000206a78b0> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x0000000020719428> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x0000000020782088> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x00000000208098c8> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x0000000020871638> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x00000000208efff8> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x000000002095fd40> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x00000000209db848> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x0000000020a52160> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x0000000020aeb348> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x0000000020b76d48> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x0000000020c07970> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x0000000020c7c988> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x0000000020d19a90> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x0000000020dc4540> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x0000000020e6bc30> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x0000000020ef0040> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x0000000020f79b58> 
##   ..$ :Classes 'tar_stem', 'tar_builder', 'tar_target', 'environment' <environment: 0x00000000211d9678>

The third argument to tar_combine says how I want the targets to be combined. This uses an operator called “unquote splice” (!!!) which is used to unquote many arguments (targets). Honestly, I only started learning about these operators, and the larger metaprogramming family they belong to fairly recently. Using targets has actually been a great driving force practice these techniques. For a good introduction though, I thought the chapters on metaprogramming in the Advanced R were very helpful. Chapter 19 in particular covers the unquote-splice and related operators.

Here I’ll take a look at what this combined target looks like.


str(tar_read(CompositeIntervalResults_Combined))
## List of 45
##  $ CompositeIntervalResults_5_10_EarHeight         :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 1.12 0.736 0.782 1.006 0.667 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:5] "PHM4134.8" "PZB01403.1" "PZA00015.5" "PZA01934.6" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  5 obs. of  2 variables:
##   .. ..$ chr: chr [1:5] "8" "1" "9" "3" ...
##   .. ..$ pos: num [1:5] 59.7 180 54 67.2 106.2
##  $ CompositeIntervalResults_5_10_LeafLength        :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.196 0.0628 0.2095 0.2847 0.1112 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:5] "PZA02269.3/4" "PZB00409.6" "PHM2343.25" "PZA01096.1" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  5 obs. of  2 variables:
##   .. ..$ chr: chr [1:5] "1" "10" "3" "9" ...
##   .. ..$ pos: num [1:5] 149.7 40.1 53.4 69.4 10
##  $ CompositeIntervalResults_5_10_LeafWidth         :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.05694 0.00872 0.00419 0.02199 0.40779 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:5] "PZA02427.1" "PZA00985.1" "PZA01497.1" "PZA01292.1" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  5 obs. of  2 variables:
##   .. ..$ chr: chr [1:5] "3" "5" "1" "10" ...
##   .. ..$ pos: num [1:5] 52.1 42.7 29.7 44.3 69.8
##  $ CompositeIntervalResults_5_10_CobWeight         :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.2839 0.42566 0.60337 0.70178 0.00438 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:5] "PZB00648.5" "PZA00824.2" "PZA00860.1" "PZA01422.3" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  5 obs. of  2 variables:
##   .. ..$ chr: chr [1:5] "1" "2" "9" "4" ...
##   .. ..$ pos: num [1:5] 33.9 105.3 32.6 47.7 156.5
##  $ CompositeIntervalResults_5_10_TotalKernelVolume :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.0599 0.04107 0.1796 0.13669 0.00608 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:5] "PZA03154.4" "PZA00382.17" "zfl2.9" "PZA02278.1" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  5 obs. of  2 variables:
##   .. ..$ chr: chr [1:5] "3" "6" "2" "1" ...
##   .. ..$ pos: num [1:5] 109.2 43.7 36.2 162.8 5.9
##  $ CompositeIntervalResults_5_15_EarHeight         :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.634 0.522 0.661 0.87 0.705 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:5] "PHM3978.104" "PHM3034.3" "PZA00015.5" "PZA01934.6" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  5 obs. of  2 variables:
##   .. ..$ chr: chr [1:5] "8" "1" "9" "3" ...
##   .. ..$ pos: num [1:5] 57.5 151.8 54 67.2 106.2
##  $ CompositeIntervalResults_5_15_LeafLength        :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.436 0.343 0.479 0.52 0.329 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:5] "PZA02269.3/4" "PZA00048.1" "PHM2343.25" "PZA00152.1" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  5 obs. of  2 variables:
##   .. ..$ chr: chr [1:5] "1" "10" "3" "9" ...
##   .. ..$ pos: num [1:5] 149.7 42.9 53.4 53.1 11.5
##  $ CompositeIntervalResults_5_15_LeafWidth         :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.4637 0.2455 0.1327 0.1161 0.0678 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:5] "PZA02427.1" "PZA00517.7" "PZA01030.1" "PZA00048.1" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  5 obs. of  2 variables:
##   .. ..$ chr: chr [1:5] "3" "5" "1" "10" ...
##   .. ..$ pos: num [1:5] 52.1 49 34.3 42.9 48
##  $ CompositeIntervalResults_5_15_CobWeight         :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.34151 0.57189 0.52988 0.59612 0.00738 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:5] "PZB00648.5" "PHM3668.12" "PHM9418.11" "PZA01284.6" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  5 obs. of  2 variables:
##   .. ..$ chr: chr [1:5] "1" "2" "1" "5" ...
##   .. ..$ pos: num [1:5] 33.9 106.1 87.3 37.9 157.6
##  $ CompositeIntervalResults_5_15_TotalKernelVolume :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 9.77e-02 6.05e-02 2.11e-01 1.50e-01 4.15e-05 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:5] "PZA03154.4" "PZA01591.1" "PZA02081.1" "PZA02278.1" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  5 obs. of  2 variables:
##   .. ..$ chr: chr [1:5] "3" "6" "2" "1" ...
##   .. ..$ pos: num [1:5] 109.2 46.3 18.3 162.8 60.6
##  $ CompositeIntervalResults_5_20_EarHeight         :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.807 0.612 0.827 1.107 0.889 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:5] "PZA03404.1" "PHM934.19" "PZA02397.1" "PHM1745.16" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  5 obs. of  2 variables:
##   .. ..$ chr: chr [1:5] "1" "8" "9" "3" ...
##   .. ..$ pos: num [1:5] 147.9 63.3 64.5 63.8 106.2
##  $ CompositeIntervalResults_5_20_LeafLength        :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.0268 0.0117 0.0663 0.1265 0.0502 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:5] "PZA02269.3/4" "PZA00814.1" "PHM2343.25" "PHM3330.25" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  5 obs. of  2 variables:
##   .. ..$ chr: chr [1:5] "1" "10" "3" "9" ...
##   .. ..$ pos: num [1:5] 149.7 41.1 53.4 63.3 10
##  $ CompositeIntervalResults_5_20_LeafWidth         :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 2.17e-01 6.54e-02 7.06e-03 2.49e-05 2.58e-01 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:5] "PZA00210.1/9" "PZA01497.1" "PZA01284.6" "PZA00337.4" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  5 obs. of  2 variables:
##   .. ..$ chr: chr [1:5] "3" "1" "5" "10" ...
##   .. ..$ pos: num [1:5] 54.3 29.7 37.9 40.6 48
##  $ CompositeIntervalResults_5_20_CobWeight         :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.192 0.197 0.191 0.246 0.186 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:5] "PZB00648.5" "PHM5181.10" "PZA00343.31" "PZB00079.4" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  5 obs. of  2 variables:
##   .. ..$ chr: chr [1:5] "1" "9" "1" "5" ...
##   .. ..$ pos: num [1:5] 33.9 26.8 197.2 36.5 18.3
##  $ CompositeIntervalResults_5_20_TotalKernelVolume :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 1.87e-01 1.87e-01 3.57e-01 3.01e-01 4.42e-05 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:5] "PZA03154.4" "PZA00473.5" "PZA00108.4" "PHM5526.25" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  5 obs. of  2 variables:
##   .. ..$ chr: chr [1:5] "3" "6" "2" "1" ...
##   .. ..$ pos: num [1:5] 109.2 45.9 38.6 157.1 5.9
##  $ CompositeIntervalResults_7_10_EarHeight         :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.665 0.485 0.475 0.679 0.491 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:7] "PHM3978.104" "PHM3034.3" "PZA00152.1" "PHM1745.16" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  7 obs. of  2 variables:
##   .. ..$ chr: chr [1:7] "8" "1" "9" "3" ...
##   .. ..$ pos: num [1:7] 57.5 151.8 53.1 63.8 110.7 ...
##  $ CompositeIntervalResults_7_10_LeafLength        :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.239 0.194 0.433 0.583 0.296 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:7] "PZA02269.3/4" "PZA00337.4" "PHM2343.25" "PZA03470.1" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  7 obs. of  2 variables:
##   .. ..$ chr: chr [1:7] "1" "10" "3" "9" ...
##   .. ..$ pos: num [1:7] 149.7 40.6 53.4 54.7 10 ...
##  $ CompositeIntervalResults_7_10_LeafWidth         :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.3834 0.1954 0.1501 0.0888 0.0453 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:7] "PZA02427.1" "PZA01030.1" "PZA03226.3" "PZA01919.2" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  7 obs. of  2 variables:
##   .. ..$ chr: chr [1:7] "3" "1" "5" "10" ...
##   .. ..$ pos: num [1:7] 52.1 34.3 50.8 44.7 46.3 ...
##  $ CompositeIntervalResults_7_10_CobWeight         :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.1813 0.2844 0.2462 0.3256 0.0155 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:7] "PZA01497.1" "PHM3055.9" "PZA00112.5" "PZA02135.2" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  7 obs. of  2 variables:
##   .. ..$ chr: chr [1:7] "1" "2" "5" "1" ...
##   .. ..$ pos: num [1:7] 29.7 103.7 41.5 92 141.9 ...
##  $ CompositeIntervalResults_7_10_TotalKernelVolume :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.06367 0.01474 0.03289 0.00982 0.23158 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:7] "PZA03154.4" "PZA01729.1" "zfl2.9" "PZA02698.3" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  7 obs. of  2 variables:
##   .. ..$ chr: chr [1:7] "3" "6" "2" "1" ...
##   .. ..$ pos: num [1:7] 109.2 45.7 36.2 164.6 5.9 ...
##  $ CompositeIntervalResults_7_15_EarHeight         :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.723 0.499 0.388 0.47 0.238 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:7] "PHM14475.7" "PHM3978.104" "PZA00015.5" "PHM1745.16" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  7 obs. of  2 variables:
##   .. ..$ chr: chr [1:7] "1" "8" "9" "3" ...
##   .. ..$ pos: num [1:7] 152.4 57.5 54 63.8 106.2 ...
##  $ CompositeIntervalResults_7_15_LeafLength        :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.602 0.423 0.828 0.825 0.347 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:7] "PZA02269.3/4" "PZA00048.1" "PHM2343.25" "PZA03470.1" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  7 obs. of  2 variables:
##   .. ..$ chr: chr [1:7] "1" "10" "3" "9" ...
##   .. ..$ pos: num [1:7] 149.7 42.9 53.4 54.7 25.4 ...
##  $ CompositeIntervalResults_7_15_LeafWidth         :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.1838 0.1004 0.0311 0.0139 0.04 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:7] "PHM2343.25" "PZA01030.1" "PZA03578.1" "PZA00814.1" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  7 obs. of  2 variables:
##   .. ..$ chr: chr [1:7] "3" "1" "5" "10" ...
##   .. ..$ pos: num [1:7] 53.4 34.3 47 41.1 89.4 ...
##  $ CompositeIntervalResults_7_15_CobWeight         :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.1134 0.1552 0.2133 0.2341 0.0897 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:7] "PZB00648.5" "PHM3668.12" "PHM1968.22" "PZA00381.4" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  7 obs. of  2 variables:
##   .. ..$ chr: chr [1:7] "1" "2" "1" "1" ...
##   .. ..$ pos: num [1:7] 33.9 106.1 98.4 140.2 128.1 ...
##  $ CompositeIntervalResults_7_15_TotalKernelVolume :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.0532 0.0256 0.0327 0.015 0.0631 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:7] "PZA03154.4" "PZA00382.17" "PZA00108.4" "PZA02698.3" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  7 obs. of  2 variables:
##   .. ..$ chr: chr [1:7] "3" "6" "2" "1" ...
##   .. ..$ pos: num [1:7] 109.2 43.7 38.6 164.6 60.6 ...
##  $ CompositeIntervalResults_7_20_EarHeight         :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.652 0.453 0.621 0.864 1.184 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:7] "PZA00429.1" "PHM3034.3" "PZA02212.1" "PZA00152.1" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  7 obs. of  2 variables:
##   .. ..$ chr: chr [1:7] "8" "1" "3" "9" ...
##   .. ..$ pos: num [1:7] 74.3 151.8 84.6 53.1 60.6 ...
##  $ CompositeIntervalResults_7_20_LeafLength        :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.0989 0.0992 0.3354 0.2932 0.04 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:7] "PZA02269.3/4" "PZA00814.1" "PHM2343.25" "PZA01096.1" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  7 obs. of  2 variables:
##   .. ..$ chr: chr [1:7] "1" "10" "3" "9" ...
##   .. ..$ pos: num [1:7] 149.7 41.1 53.4 69.4 11.5 ...
##  $ CompositeIntervalResults_7_20_LeafWidth         :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.3644 0.1879 0.1113 0.1027 0.0649 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:7] "PHM4145.18" "PZA01497.1" "PZA00112.5" "PZA01919.2" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  7 obs. of  2 variables:
##   .. ..$ chr: chr [1:7] "3" "1" "5" "10" ...
##   .. ..$ pos: num [1:7] 50.2 29.7 41.5 44.7 48 ...
##  $ CompositeIntervalResults_7_20_CobWeight         :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.256 0.315442 0.399834 0.487409 0.000898 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:7] "PZB00648.5" "PZA00824.2" "PHM9374.5" "PZA01422.3" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  7 obs. of  2 variables:
##   .. ..$ chr: chr [1:7] "1" "2" "9" "4" ...
##   .. ..$ pos: num [1:7] 33.9 105.3 31.2 47.7 42.7 ...
##  $ CompositeIntervalResults_7_20_TotalKernelVolume :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.0362 0.0267 0.0669 0.0351 0.0422 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:7] "PZA00892.5" "PZA00382.17" "PZA02698.3" "zfl2.9" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  7 obs. of  2 variables:
##   .. ..$ chr: chr [1:7] "3" "6" "1" "2" ...
##   .. ..$ pos: num [1:7] 107.7 43.7 164.6 36.2 5.9 ...
##  $ CompositeIntervalResults_10_10_EarHeight        :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.589 0.302 0.364 0.645 0.222 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:10] "PHM14475.7" "PZA02683.1" "PZA02613.1" "PHM1745.16" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  10 obs. of  2 variables:
##   .. ..$ chr: chr [1:10] "1" "8" "9" "3" ...
##   .. ..$ pos: num [1:10] 152.4 56 57.3 63.8 101.9 ...
##  $ CompositeIntervalResults_10_10_LeafLength       :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.118 0.161 0.283 0.472 0.115 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:10] "PZA02269.3/4" "PZA01877.2" "PHM2343.25" "PHM3330.25" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  10 obs. of  2 variables:
##   .. ..$ chr: chr [1:10] "1" "10" "3" "9" ...
##   .. ..$ pos: num [1:10] 149.7 38.6 53.4 63.3 5.7 ...
##  $ CompositeIntervalResults_10_10_LeafWidth        :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.2969 0.2037 0.099 0.0664 0.0731 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:10] "PZA02427.1" "PZA00517.7" "PZA01497.1" "PZA00814.1" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  10 obs. of  2 variables:
##   .. ..$ chr: chr [1:10] "3" "5" "1" "10" ...
##   .. ..$ pos: num [1:10] 52.1 49 29.7 41.1 48 ...
##  $ CompositeIntervalResults_10_10_CobWeight        :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.226644 0.329982 0.286879 0.284872 0.000126 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:10] "PZB00648.5" "PZA00824.2" "PZA00112.5" "PZB01235.4" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  10 obs. of  2 variables:
##   .. ..$ chr: chr [1:10] "1" "2" "5" "1" ...
##   .. ..$ pos: num [1:10] 33.9 105.3 41.5 86.6 128.1 ...
##  $ CompositeIntervalResults_10_10_TotalKernelVolume:Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.2397 0.1161 0.2176 0.1674 0.0382 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:10] "PZA01457.1" "PZA01729.1" "PZB00114.1" "zfl2.9" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  10 obs. of  2 variables:
##   .. ..$ chr: chr [1:10] "3" "6" "1" "2" ...
##   .. ..$ pos: num [1:10] 104 45.7 169.1 36.2 5.9 ...
##  $ CompositeIntervalResults_10_15_EarHeight        :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 1.571 0.982 0.824 0.908 0.486 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:10] "PHM14475.7" "PHM4134.8" "PZA03032.19" "PHM4905.6" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  10 obs. of  2 variables:
##   .. ..$ chr: chr [1:10] "1" "8" "3" "9" ...
##   .. ..$ pos: num [1:10] 152.4 59.7 82.1 64.3 101.9 ...
##  $ CompositeIntervalResults_10_15_LeafLength       :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.285 0.207 0.518 0.66 0.129 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:10] "PHM14475.7" "PZA03491.1" "PZA03670.1" "PHM1745.16" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  10 obs. of  2 variables:
##   .. ..$ chr: chr [1:10] "1" "10" "9" "3" ...
##   .. ..$ pos: num [1:10] 152.4 36.2 65.5 63.8 10 ...
##  $ CompositeIntervalResults_10_15_LeafWidth        :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.2449 0.08861 0.01101 0.00407 0.00343 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:10] "PZA00210.1/9" "PZA03578.1" "PZA01030.1" "PZB00409.6" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  10 obs. of  2 variables:
##   .. ..$ chr: chr [1:10] "3" "5" "1" "10" ...
##   .. ..$ pos: num [1:10] 54.3 47 34.3 40.1 48 ...
##  $ CompositeIntervalResults_10_15_CobWeight        :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.28548 0.37096 0.3707 0.32613 0.00655 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:10] "PZA01030.1" "PHM3668.12" "PZA00112.5" "PHM9418.11" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  10 obs. of  2 variables:
##   .. ..$ chr: chr [1:10] "1" "2" "5" "1" ...
##   .. ..$ pos: num [1:10] 34.3 106.1 41.5 87.3 149.7 ...
##  $ CompositeIntervalResults_10_15_TotalKernelVolume:Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.0541 0.065 0.1798 0.1408 0.0274 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:10] "PZA03154.4" "PZA01552.1" "zfl2.9" "PZA02698.3" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  10 obs. of  2 variables:
##   .. ..$ chr: chr [1:10] "3" "6" "2" "1" ...
##   .. ..$ pos: num [1:10] 109.2 48 36.2 164.6 8.9 ...
##  $ CompositeIntervalResults_10_20_EarHeight        :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.00551 0.00261 0.0179 0.04365 0.26569 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:10] "PZA02269.3/4" "PHM4757.14" "PZA03032.19" "PZA00152.1" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  10 obs. of  2 variables:
##   .. ..$ chr: chr [1:10] "1" "8" "3" "9" ...
##   .. ..$ pos: num [1:10] 149.7 80.2 82.1 53.1 60.6 ...
##  $ CompositeIntervalResults_10_20_LeafLength       :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.098 0.0693 0.2235 0.2071 0.1098 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:10] "PZA02269.3/4" "PZB00409.6" "PZA03235.1" "PZA01934.6" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  10 obs. of  2 variables:
##   .. ..$ chr: chr [1:10] "1" "10" "9" "3" ...
##   .. ..$ pos: num [1:10] 149.7 40.1 56.7 67.2 10 ...
##  $ CompositeIntervalResults_10_20_LeafWidth        :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 1.77e-01 4.03e-02 1.15e-05 4.26e-03 1.02e-01 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:10] "PZA02427.1" "PZA01497.1" "PZA00517.7" "PZB00409.6" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  10 obs. of  2 variables:
##   .. ..$ chr: chr [1:10] "3" "1" "5" "10" ...
##   .. ..$ pos: num [1:10] 52.1 29.7 49 40.1 48 ...
##  $ CompositeIntervalResults_10_20_CobWeight        :Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.166 0.108 0.131 0.139 0.294 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:10] "PZB00648.5" "PZA00824.2" "PZA03058.22/21" "PZA01422.3" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  10 obs. of  2 variables:
##   .. ..$ chr: chr [1:10] "1" "2" "9" "4" ...
##   .. ..$ pos: num [1:10] 33.9 105.3 34.5 47.7 136.6 ...
##  $ CompositeIntervalResults_10_20_TotalKernelVolume:Classes 'scanone' and 'data.frame':  1106 obs. of  3 variables:
##   ..$ chr: Factor w/ 10 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ pos: num [1:1106] 0 0.9 3.7 5.1 9.7 ...
##   ..$ lod: num [1:1106] 0.12382 0.13622 0.25934 0.21306 0.00104 ...
##   ..- attr(*, "method")= chr "em"
##   ..- attr(*, "type")= chr "riself"
##   ..- attr(*, "model")= chr "normal"
##   ..- attr(*, "marker.covar")= chr [1:10] "PZA03154.4" "PZA00571.1" "PHM5822.15" "PZA02698.3" ...
##   ..- attr(*, "marker.covar.pos")='data.frame':  10 obs. of  2 variables:
##   .. ..$ chr: chr [1:10] "3" "6" "2" "1" ...
##   .. ..$ pos: num [1:10] 109.2 44.6 29.8 164.6 0 ...


You can see that this target is a simple list of the cim scanone objects, where each list element is named with its target name. This is very useful because the target names contain information about the model parameters used to create the output. This convention allows information about the parameters to be carried forward in the analysis.

This pattern of defining many targets according to parameter options, and then combining the results of those many targets allows a user to quickly generate and keep track of many QTL mapping experiments. By making a single parameter table and calling two functions, you can have an organized list of QTL mapping results in hand and ready for comparison.

Other benefits of targets

The availability of tools like tar_map and tar_combine to improve workflow efficiency is arguably one of the least special aspects of targets. With some creative use of functional programming, anyone can mimic the same steps and get identical results with a standard script. Targets improves upon traditional workflows by providing tools that help you to massively reduce the cognitive load of these projects that can quickly become confusing, especially if you’re new to mapping experiments (again, speaking from personal experience).

The user manual, (see chapters 1 and 4 especially), does a good job of justifying the use of the package.

To do

  • Visualizing results (ggplot, echarts, look into using shiny within markdown for more interactivity)
  • MQM mapping
  • Imputation step (for MQM mapping)
  • Summary function (fitqtl)
  • Parallel processing (Maybe HPC too at some point)

Reproducibility

Reproducibility receipt
## [1] "2021-03-23 15:56:42 EDT"
## Local:    main C:/Users/Jay/Desktop/Documents/R/QTL_targets_workflow
## Remote:   main @ origin (https://github.com/jhgille2/QTL_targets_workflow.git)
## Head:     [160198d] 2021-03-23: blah blah
## R version 4.0.2 (2020-06-22)
## Platform: x86_64-w64-mingw32/x64 (64-bit)
## Running under: Windows 10 x64 (build 19042)
## 
## Matrix products: default
## 
## locale:
## [1] LC_COLLATE=English_United States.1252 
## [2] LC_CTYPE=English_United States.1252   
## [3] LC_MONETARY=English_United States.1252
## [4] LC_NUMERIC=C                          
## [5] LC_TIME=English_United States.1252    
## 
## attached base packages:
## [1] grid      stats     graphics  grDevices utils     datasets  methods  
## [8] base     
## 
## other attached packages:
##  [1] DiagrammeR_1.0.6.1   echarts4r_0.3.3      LinkageMapView_2.1.2
##  [4] qtlDesign_0.941      magrittr_2.0.1       here_1.0.1          
##  [7] ASMap_1.0-4          lattice_0.20-41      RColorBrewer_1.1-2  
## [10] fields_11.6          spam_2.6-0           dotCall64_1.0-0     
## [13] gtools_3.8.2         forcats_0.5.1        stringr_1.4.0       
## [16] dplyr_1.0.4          purrr_0.3.4          readr_1.4.0         
## [19] tidyr_1.1.2          tibble_3.0.6         ggplot2_3.3.3       
## [22] tidyverse_1.3.0      qtl_1.47-9           rmarkdown_2.6       
## [25] tarchetypes_0.0.4    targets_0.1.0.9000   dotenv_1.0.2        
## [28] conflicted_1.0.4    
## 
## loaded via a namespace (and not attached):
##  [1] fs_1.5.0          lubridate_1.7.9.2 httr_1.4.2        rprojroot_2.0.2  
##  [5] tools_4.0.2       backports_1.2.1   utf8_1.1.4        R6_2.5.0         
##  [9] DBI_1.1.0         colorspace_2.0-0  withr_2.4.1       tidyselect_1.1.0 
## [13] processx_3.4.5    git2r_0.27.1      compiler_4.0.2    cli_2.3.1        
## [17] rvest_0.3.6       xml2_1.3.2        scales_1.1.1      callr_3.5.1      
## [21] digest_0.6.27     pkgconfig_2.0.3   htmltools_0.5.1.1 dbplyr_2.0.0     
## [25] fastmap_1.1.0     maps_3.3.0        htmlwidgets_1.5.3 rlang_0.4.10     
## [29] readxl_1.3.1      rstudioapi_0.13   shiny_1.6.0       visNetwork_2.0.9 
## [33] generics_0.1.0    jsonlite_1.7.2    Rcpp_1.0.6        munsell_0.5.0    
## [37] fansi_0.4.2       lifecycle_1.0.0   yaml_2.2.1        stringi_1.5.3    
## [41] parallel_4.0.2    promises_1.2.0.1  crayon_1.4.1      haven_2.3.1      
## [45] hms_1.0.0         knitr_1.31        ps_1.5.0          pillar_1.5.0     
## [49] igraph_1.2.6      codetools_0.2-16  reprex_0.3.0      glue_1.4.2       
## [53] evaluate_0.14     data.table_1.13.6 modelr_0.1.8      vctrs_0.3.6      
## [57] httpuv_1.5.5      cellranger_1.1.0  gtable_0.3.0      assertthat_0.2.1 
## [61] cachem_1.0.3      xfun_0.21         mime_0.10         xtable_1.8-4     
## [65] broom_0.7.5       later_1.1.0.1     memoise_2.0.0     ellipsis_0.3.1